home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
-
- This file is part of AFPL Ghostscript.
-
- AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
- distributor accepts any responsibility for the consequences of using it, or
- for whether it serves any particular purpose or works at all, unless he or
- she says so in writing. Refer to the Aladdin Free Public License (the
- "License") for full details.
-
- Every copy of AFPL Ghostscript must include a copy of the License, normally
- in a plain ASCII text file named PUBLIC. The License grants you the right
- to copy, modify and redistribute AFPL Ghostscript, but only under certain
- conditions described in the License. Among other things, the License
- requires that the copyright notice and this notice be preserved on all
- copies.
- */
-
- /*$Id: zdpnext.c,v 1.3 2000/09/21 15:12:01 rayjj Exp $ */
- /* NeXT Display PostScript extensions */
- #include "math_.h"
- #include "ghost.h"
- #include "oper.h"
- #include "gscoord.h"
- #include "gscspace.h" /* for iimage.h */
- #include "gsdpnext.h"
- #include "gsmatrix.h"
- #include "gsiparam.h" /* for iimage.h */
- #include "gsiparm2.h"
- #include "gspath2.h"
- #include "gxcvalue.h"
- #include "gxdevice.h"
- #include "gxsample.h"
- #include "ialloc.h"
- #include "igstate.h"
- #include "iimage.h"
- #include "iimage2.h"
- #include "store.h"
-
- /* ------ alpha channel ------ */
-
- /* - currentalpha <alpha> */
- private int
- zcurrentalpha(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
-
- push(1);
- make_real(op, gs_currentalpha(igs));
- return 0;
- }
-
- /* <alpha> setalpha - */
- private int
- zsetalpha(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- double alpha;
- int code;
-
- if (real_param(op, &alpha) < 0)
- return_op_typecheck(op);
- if ((code = gs_setalpha(igs, alpha)) < 0)
- return code;
- pop(1);
- return 0;
- }
-
- /* ------ Imaging/compositing ------ */
-
- /*
- * Miscellaneous notes:
- *
- * composite / dissolve respect destination clipping (both clip & viewclip),
- * but ignore source clipping.
- * composite / dissolve must handle overlapping source/destination correctly.
- * compositing converts the source to the destination's color model
- * (including halftoning if needed).
- */
-
- /* Imported procedures */
- int zimage_multiple(P2(i_ctx_t *i_ctx_p, bool has_alpha)); /* in zcolor1.c */
-
- /*
- * Define the operand and bookeeping structure for a compositing operation.
- */
- typedef struct alpha_composite_state_s {
- /* Compositing parameters */
- gs_composite_alpha_params_t params;
- /* Temporary structures */
- gs_composite_t *pcte;
- gx_device *cdev;
- gx_device *orig_dev;
- } alpha_composite_state_t;
-
- /* Forward references */
- private int begin_composite(P2(i_ctx_t *, alpha_composite_state_t *));
- private void end_composite(P2(i_ctx_t *, alpha_composite_state_t *));
- private int xywh_param(P2(os_ptr, double[4]));
-
- /* <width> <height> <bits/comp> <matrix> */
- /* <datasrc_0> ... <datasrc_ncomp-1> true <ncomp> alphaimage - */
- /* <datasrc> false <ncomp> alphaimage - */
- private int
- zalphaimage(i_ctx_t *i_ctx_p)
- {
- /* Essentially the whole implementation is shared with colorimage. */
- return zimage_multiple(i_ctx_p, true);
- }
-
- /* <destx> <desty> <width> <height> <op> compositerect - */
- private int
- zcompositerect(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- double dest_rect[4];
- alpha_composite_state_t cstate;
- int code = xywh_param(op - 1, dest_rect);
-
- if (code < 0)
- return code;
- check_int_leu(*op, compositerect_last);
- cstate.params.op = (gs_composite_op_t) op->value.intval;
- code = begin_composite(i_ctx_p, &cstate);
- if (code < 0)
- return code;
- {
- gs_rect rect;
-
- rect.q.x = (rect.p.x = dest_rect[0]) + dest_rect[2];
- rect.q.y = (rect.p.y = dest_rect[1]) + dest_rect[3];
- code = gs_rectfill(igs, &rect, 1);
- }
- end_composite(i_ctx_p, &cstate);
- if (code >= 0)
- pop(5);
- return code;
- }
-
- /* Common code for composite and dissolve. */
- private int
- composite_image(i_ctx_t *i_ctx_p, const gs_composite_alpha_params_t * params)
- {
- os_ptr op = osp;
- alpha_composite_state_t cstate;
- gs_image2_t image;
- double src_rect[4];
- double dest_pt[2];
- gs_matrix save_ctm;
- int code = xywh_param(op - 4, src_rect);
-
- cstate.params = *params;
- gs_image2_t_init(&image);
- if (code < 0 ||
- (code = num_params(op - 1, 2, dest_pt)) < 0
- )
- return code;
- if (r_has_type(op - 3, t_null))
- image.DataSource = igs;
- else {
- check_stype(op[-3], st_igstate_obj);
- check_read(op[-3]);
- image.DataSource = igstate_ptr(op - 3);
- }
- image.XOrigin = src_rect[0];
- image.YOrigin = src_rect[1];
- image.Width = src_rect[2];
- image.Height = src_rect[3];
- image.PixelCopy = true;
- /* Compute appropriate transformations. */
- gs_currentmatrix(igs, &save_ctm);
- gs_translate(igs, dest_pt[0], dest_pt[1]);
- gs_make_identity(&image.ImageMatrix);
- if (image.DataSource == igs) {
- image.XOrigin -= dest_pt[0];
- image.YOrigin -= dest_pt[1];
- }
- code = begin_composite(i_ctx_p, &cstate);
- if (code >= 0) {
- code = process_non_source_image(i_ctx_p,
- (const gs_image_common_t *)&image,
- "composite_image");
- end_composite(i_ctx_p, &cstate);
- if (code >= 0)
- pop(8);
- }
- gs_setmatrix(igs, &save_ctm);
- return code;
- }
-
- /* <srcx> <srcy> <width> <height> <srcgstate|null> <destx> <desty> <op> */
- /* composite - */
- private int
- zcomposite(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- gs_composite_alpha_params_t params;
-
- check_int_leu(*op, composite_last);
- params.op = (gs_composite_op_t) op->value.intval;
- return composite_image(i_ctx_p, ¶ms);
- }
-
- /* <srcx> <srcy> <width> <height> <srcgstate|null> <destx> <desty> <delta> */
- /* dissolve - */
- private int
- zdissolve(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- gs_composite_alpha_params_t params;
- double delta;
- int code = real_param(op, &delta);
-
- if (code < 0)
- return code;
- if (delta < 0 || delta > 1)
- return_error(e_rangecheck);
- params.op = composite_Dissolve;
- params.delta = delta;
- return composite_image(i_ctx_p, ¶ms);
- }
-
- /* ------ Image reading ------ */
-
- private int device_is_true_color(P1(gx_device * dev));
-
- /* <x> <y> <width> <height> <matrix> .sizeimagebox */
- /* <dev_x> <dev_y> <dev_width> <dev_height> <matrix> */
- private void box_confine(P3(int *pp, int *pq, int wh));
- private int
- zsizeimagebox(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- const gx_device *dev = gs_currentdevice(igs);
- gs_rect srect, drect;
- gs_matrix mat;
- gs_int_rect rect;
- int w, h;
- int code;
-
- check_type(op[-4], t_integer);
- check_type(op[-3], t_integer);
- check_type(op[-2], t_integer);
- check_type(op[-1], t_integer);
- srect.p.x = op[-4].value.intval;
- srect.p.y = op[-3].value.intval;
- srect.q.x = srect.p.x + op[-2].value.intval;
- srect.q.y = srect.p.y + op[-1].value.intval;
- gs_currentmatrix(igs, &mat);
- gs_bbox_transform(&srect, &mat, &drect);
- /*
- * We want the dimensions of the image as a source, not a
- * destination, so we need to expand it rather than pixround.
- */
- rect.p.x = (int)floor(drect.p.x);
- rect.p.y = (int)floor(drect.p.y);
- rect.q.x = (int)ceil(drect.q.x);
- rect.q.y = (int)ceil(drect.q.y);
- /*
- * Clip the rectangle to the device boundaries, since that's what
- * the NeXT implementation does.
- */
- box_confine(&rect.p.x, &rect.q.x, dev->width);
- box_confine(&rect.p.y, &rect.q.y, dev->height);
- w = rect.q.x - rect.p.x;
- h = rect.q.y - rect.p.y;
- /*
- * The NeXT documentation doesn't specify very clearly what is
- * supposed to be in the matrix: the following produces results
- * that match testing on an actual NeXT system.
- */
- mat.tx -= rect.p.x;
- mat.ty -= rect.p.y;
- code = write_matrix(op, &mat);
- if (code < 0)
- return code;
- make_int(op - 4, rect.p.x);
- make_int(op - 3, rect.p.y);
- make_int(op - 2, w);
- make_int(op - 1, h);
- return 0;
- }
- private void
- box_confine(int *pp, int *pq, int wh)
- {
- if ( *pq <= 0 )
- *pp = *pq = 0;
- else if ( *pp >= wh )
- *pp = *pq = wh;
- else {
- if ( *pp < 0 )
- *pp = 0;
- if ( *pq > wh )
- *pq = wh;
- }
- }
-
- /* - .sizeimageparams <bits/sample> <multiproc> <ncolors> */
- private int
- zsizeimageparams(i_ctx_t *i_ctx_p)
- {
- os_ptr op = osp;
- gx_device *dev = gs_currentdevice(igs);
- int ncomp = dev->color_info.num_components;
- int bps;
-
- push(3);
- if (device_is_true_color(dev))
- bps = dev->color_info.depth / ncomp;
- else {
- /*
- * Set bps to the smallest allowable number of bits that is
- * sufficient to represent the number of different colors.
- */
- gx_color_value max_value =
- (dev->color_info.num_components == 1 ?
- dev->color_info.max_gray :
- max(dev->color_info.max_gray, dev->color_info.max_color));
- static const gx_color_value sizes[] = {
- 1, 2, 4, 8, 12, sizeof(gx_max_color_value) * 8
- };
- int i;
-
- for (i = 0;; ++i)
- if (max_value <= ((ulong) 1 << sizes[i]) - 1)
- break;
- bps = sizes[i];
- }
- make_int(op - 2, bps);
- make_false(op - 1);
- make_int(op, ncomp);
- return 0;
- }
-
- /* ------ Initialization procedure ------ */
-
- const op_def zdpnext_op_defs[] =
- {
- {"0currentalpha", zcurrentalpha},
- {"1setalpha", zsetalpha},
- {"7alphaimage", zalphaimage},
- {"8composite", zcomposite},
- {"5compositerect", zcompositerect},
- {"8dissolve", zdissolve},
- {"5.sizeimagebox", zsizeimagebox},
- {"0.sizeimageparams", zsizeimageparams},
- op_def_end(0)
- };
-
- /* ------ Internal routines ------ */
-
- /* Collect a rect operand. */
- private int
- xywh_param(os_ptr op, double rect[4])
- {
- int code = num_params(op, 4, rect);
-
- if (code < 0)
- return code;
- if (rect[2] < 0)
- rect[0] += rect[2], rect[2] = -rect[2];
- if (rect[3] < 0)
- rect[1] += rect[3], rect[3] = -rect[3];
- return code;
- }
-
- /* Begin a compositing operation. */
- private int
- begin_composite(i_ctx_t *i_ctx_p, alpha_composite_state_t * pcp)
- {
- gx_device *dev = gs_currentdevice(igs);
- int code =
- gs_create_composite_alpha(&pcp->pcte, &pcp->params, imemory);
-
- if (code < 0)
- return code;
- pcp->orig_dev = pcp->cdev = dev; /* for end_composite */
- code = (*dev_proc(dev, create_compositor))
- (dev, &pcp->cdev, pcp->pcte, (const gs_imager_state *)igs,
- imemory);
- if (code < 0) {
- end_composite(i_ctx_p, pcp);
- return code;
- }
- gs_setdevice_no_init(igs, pcp->cdev);
- return 0;
- }
-
- /* End a compositing operation. */
- private void
- end_composite(i_ctx_t *i_ctx_p, alpha_composite_state_t * pcp)
- {
- /* Close and free the compositor and the compositing object. */
- if (pcp->cdev != pcp->orig_dev) {
- gs_closedevice(pcp->cdev); /* also frees the device */
- gs_setdevice_no_init(igs, pcp->orig_dev);
- }
- ifree_object(pcp->pcte, "end_composite(gs_composite_t)");
- }
-
- /*
- * Determine whether a device has decomposed pixels with the components
- * in the standard PostScript order, and a 1-for-1 color map
- * (possibly inverted). Return 0 if not true color, 1 if true color,
- * -1 if inverted true color.
- */
- private int
- device_is_true_color(gx_device * dev)
- {
- int ncomp = dev->color_info.num_components;
- int depth = dev->color_info.depth;
- int i, max_v;
-
- #define CV(i) (gx_color_value)((ulong)gx_max_color_value * i / max_v)
- #define CV0 ((gx_color_value)0)
-
- /****** DOESN'T HANDLE INVERSION YET ******/
- switch (ncomp) {
- case 1: /* gray-scale */
- max_v = dev->color_info.max_gray;
- if (max_v != (1 << depth) - 1)
- return 0;
- for (i = 0; i <= max_v; ++i) {
- gx_color_value v = CV(i);
-
- if ((*dev_proc(dev, map_rgb_color)) (dev, v, v, v) != i)
- return 0;
- }
- return true;
- case 3: /* RGB */
- max_v = dev->color_info.max_color;
- if (depth % 3 != 0 || max_v != (1 << (depth / 3)) - 1)
- return false;
- {
- const int gs = depth / 3, rs = gs * 2;
-
- for (i = 0; i <= max_v; ++i) {
- gx_color_value v = CV(i);
-
- if ((*dev_proc(dev, map_rgb_color)) (dev, v, CV0, CV0) !=
- i << rs ||
- (*dev_proc(dev, map_rgb_color)) (dev, CV0, v, CV0) !=
- i << gs ||
- (*dev_proc(dev, map_rgb_color)) (dev, CV0, CV0, v) !=
- i /*<< bs */
- )
- return 0;
- }
- }
- return true;
- case 4: /* CMYK */
- max_v = dev->color_info.max_color;
- if ((depth & 3) != 0 || max_v != (1 << (depth / 4)) - 1)
- return false;
- {
- const int ys = depth / 4, ms = ys * 2, cs = ys * 3;
-
- for (i = 0; i <= max_v; ++i) {
- gx_color_value v = CV(i);
-
- if ((*dev_proc(dev, map_cmyk_color)) (dev, v, CV0, CV0, CV0) !=
- i << cs ||
- (*dev_proc(dev, map_cmyk_color)) (dev, CV0, v, CV0, CV0) !=
- i << ms ||
- (*dev_proc(dev, map_cmyk_color)) (dev, CV0, CV0, v, CV0) !=
- i << ys ||
- (*dev_proc(dev, map_cmyk_color)) (dev, CV0, CV0, CV0, v) !=
- i /*<< ks */
- )
- return 0;
- }
- }
- return 1;
- default:
- return 0; /* DeviceN */
- }
- #undef CV
- #undef CV0
- }
-